package com.kang.c0c.optimize;

import java.util.HashSet;

import com.kang.c0c.symbol.Symbol;
import com.kang.c0c.tree.node.BinaryNode;
import com.kang.c0c.tree.node.LeafNode;
import com.kang.c0c.tree.node.Node;
import com.kang.c0c.tree.node.Nodes;
import com.kang.c0c.tree.node.SimpleBlock;

public class DataRecode {
	private SimpleBlock simple;
	
	private HashSet<Symbol> define;
	private HashSet<Symbol> use;
	private HashSet<Symbol> in;
	private HashSet<Symbol> out = null;
	
	public DataRecode(SimpleBlock simple){
		this.simple = simple;
	}
	
	public void initDefUse(){
		define = new HashSet<Symbol>();
		use = new HashSet<Symbol>();
		
		int length=simple.binarySize();
		for(int i=0;i<length;i++){
			BinaryNode binary = simple.getBinary(i);
			Node right = binary.getRight();
			if((right != null)
					&&(right instanceof LeafNode)){
				LeafNode leaf = (LeafNode)right;
				if(leaf.getNode() == Nodes.VAR){
					Symbol sym = (Symbol)leaf.getValue();
					
					if((Symbol.isVar(sym))
							&&(sym.getPos() != -1)
							&&(! define.contains(sym)))
						use.add((Symbol)leaf.getValue());
				}
			}
			
			if((binary.getNode() == Nodes.EVA)||
					(binary.getNode() == Nodes.SCAN)){
				LeafNode left = (LeafNode)binary.getLeft();
				Symbol sym = (Symbol)left.getValue();
				
				if((Symbol.isVar(sym))
						&&(sym.getPos() != -1)
						&&(!use.contains(sym)))
					define.add((Symbol)left.getValue());
			}else{
				Node left = binary.getLeft();
				
				if(left instanceof LeafNode){
					LeafNode leaf = (LeafNode)left;
					if(leaf.getNode() == Nodes.VAR){
						Symbol sym = (Symbol)leaf.getValue();
						
						if((Symbol.isVar(sym))
								&&(sym.getPos() != -1)
								&&(! define.contains(sym)))
							use.add((Symbol)leaf.getValue());
					}
				}
			}
		}
	}
	
	/**
	 * 继承自由上往下传过来的变量使用信息，主要是为了调节循环体内的活跃变量
	 * 
	 * @param simple
	 */
	public void mergeDefUse(HashSet<Symbol> def, HashSet<Symbol> use){
		HashSet<Symbol> temp = new HashSet<Symbol>(this.use);
		temp.removeAll(def);
		use.addAll(temp);
		def.addAll(this.define);
	}
	
	/**
	 * out[B] = U<B的后继S> in[S]
	 * 
	 * @param in
	 */
	public void addOut(HashSet<Symbol> in){
		if(out == null){
			out = new HashSet<Symbol>();
		}
		
		if(in != null)
			out.addAll(in);
	}
	
	/**
	 * in[B] = use[B]U(out[B]-def[B])
	 */
	public void computeIn(){
		in = new HashSet<Symbol>(use);
		HashSet<Symbol> temp = new HashSet<Symbol>(out);
		temp.removeAll(define);
		in.addAll(temp);
		
		use.clear();
		define.clear();
		use = null;
		define = null;
	}
	
	public HashSet<Symbol> getIn() {
		return in;
	}

	public HashSet<Symbol> getOut() {
		return out;
	}

	public SimpleBlock getSimple() {
		return simple;
	}
	
	public HashSet<Symbol> getDefine() {
		return define;
	}
	
	public HashSet<Symbol> getUse() {
		return use;
	}

	public void setUse(HashSet<Symbol> use) {
		this.use = use;
	}

	public void setIn(HashSet<Symbol> in) {
		this.in = in;
	}

	public void setOut(HashSet<Symbol> out) {
		this.out = out;
	}
	
	public void setSimple(SimpleBlock simple) {
		this.simple = simple;
	}
	
	public void setDefine(HashSet<Symbol> define) {
		this.define = define;
	}
}
